package com.jiajunsong.blog.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.AuthenticationFailureHandler;
import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutSuccessHandler;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;
import org.springframework.social.security.SpringSocialConfigurer;

import com.jiajunsong.blog.authentication.mobile.SmsCodeAuthenticationSecurityConfig;
import com.jiajunsong.blog.filter.ValidateCodeFilter;

@Configuration
@EnableConfigurationProperties(BlogProperty.class)
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	@Autowired
	private AuthenticationSuccessHandler authenticationSuccessHandler;
	
	@Autowired
	private AuthenticationFailureHandler authenticationFailureHandler;
	
	@Autowired
	private LogoutSuccessHandler logoutSuccessHandler;
	
	@Autowired
	private DataSource dataSource;
	@Autowired
	private UserDetailsService userDetailsService;
	
	@Autowired(required=false)
	private ValidateCodeFilter validateCodeFilter;
	
	@Autowired
	private SmsCodeAuthenticationSecurityConfig smsCodeAuthenticationSecurityConfig;
	
	@Autowired
	private SpringSocialConfigurer springSocialConfigurer;
	
	@Bean
	public PasswordEncoder passwordEncoder() {
		return new BCryptPasswordEncoder();
	}
	

	@Override
	protected void configure(HttpSecurity http) throws Exception {
		http
		.apply(smsCodeAuthenticationSecurityConfig)
		.and()
		.apply(springSocialConfigurer)
		.and()
		//.addFilterBefore(validateCodeFilter, UsernamePasswordAuthenticationFilter.class)
		.authorizeRequests()
		.antMatchers("/login","/hello","/index.html","/*.js","/*.css","/favicon.ico","/assets/**","/","/login.html")
		//最好能够找到一种配置方法，对static文件夹下的资源不拦截，如果spring security是对路径请求的路径进行分析后进行拦截的话，应该没有这种配置方法
		//对于一个博客应用，应该只拦截几个关键的API，大部分接口应该都是不用登录就能访问的，要不然不登录就看不了博客里
		.permitAll()
		.antMatchers("/hello","/hello.html")
		.authenticated()
		.and()
		.formLogin()
			.loginPage("/login")
			.successHandler(authenticationSuccessHandler)
			.failureHandler(authenticationFailureHandler)
			.and()
		.rememberMe()
			.tokenRepository(persistentTokenRepository())
			.tokenValiditySeconds(36000)//记住我的有效时间10小时
			.userDetailsService(userDetailsService)
			.and()
		.sessionManagement()
			.maximumSessions(1)
			.and()
			.and()
		.logout()
			.logoutSuccessHandler(logoutSuccessHandler)
			.and()
		.csrf().disable();
	}
	
	@Bean
	public PersistentTokenRepository persistentTokenRepository() {
		JdbcTokenRepositoryImpl tokenRepository = new JdbcTokenRepositoryImpl();
		tokenRepository.setDataSource(dataSource);
		//tokenRepository.setCreateTableOnStartup(true);//这句只能执行一次，表只能建一次
		return tokenRepository;
	}
	
	/**
     * 需要配置这个支持password模式
     * support password grant type
     * @return
     * @throws Exception
     */
    @Override
    @Bean
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }

}
